package org.qdog.pk.pkscrape.util;

import org.apache.log4j.Logger;
import org.qdog.pk.pkscrape.entity.Entity;
import org.qdog.pk.pkscrape.entity.Relationship;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @since 08/2011
 */
public class RelationshipMap {
  private static final Logger LOG = Logger.getLogger(RelationshipMap.class);
  private final Entity sourceEntity;
  private final Map<Class<? extends Relationship>, Map<String, Relationship>> relationshipByType = new HashMap<Class<? extends Relationship>, Map<String, Relationship>>();

  public RelationshipMap(Entity sourceEntity, Collection<Relationship> relationships) {
    this.sourceEntity = sourceEntity;
    for (Relationship r : relationships) {
      addRelationship(r);
    }
  }

  private void addRelationship(Relationship relationship) {
    getRelationshipsByType(relationship.getClass()).put(extractTargetEntityId(relationship), relationship);
  }

  private void removeRelationship(Relationship relationship) {
    getRelationshipsByType(relationship.getClass()).remove(extractTargetEntityId(relationship));
  }

  public Map<String, Relationship> getRelationshipsByType(Class<? extends Relationship> relationshipClass) {
    Map<String, Relationship> result = relationshipByType.get(relationshipClass);
    if (result == null) {
      result = new HashMap<String, Relationship>();
      relationshipByType.put(relationshipClass, result);
    }
    return result;
  }

  private String extractTargetEntityId(Relationship r) {
    String targetEntityId = r.getTargetEntityId();
    if (targetEntityId.equals(sourceEntity.getId())) {
      targetEntityId = r.getSourceEntityId();
    }
    return targetEntityId;
  }

  public Collection<String> getTargetEntityIdsByRelationshipType(Class<? extends Relationship> relationshipClass) {
    Collection<String> targetEntityIds = new ArrayList<String>(getRelationshipsByType(relationshipClass).size());
    for (String id : getRelationshipsByType(relationshipClass).keySet()) {
      targetEntityIds.add(id);
    }
    return targetEntityIds;
  }

  public Relationship addRelationship(Class<? extends Relationship> relationshipClass, Entity targetEntity) {
    Relationship r;
    try {
      r = relationshipClass.newInstance();
    } catch (Exception e) {
      // this should never happen!
      LOG.error("Could not create new instance of Relationship class", e);
      throw new RuntimeException("Could not create new instance of Relationship class", e);
    }
    r.setStart(new Date());
    r.setSourceEntity(sourceEntity);
    r.setTargetEntity(targetEntity);
    addRelationship(r);
    return r;
  }

  public void removeRelationshipByTargetEntity(Class<? extends Relationship> relationshipClass, String id) {
    Relationship r = getRelationshipByTargetEntity(relationshipClass, id);
    if (r != null) {
      removeRelationship(r);
    }
  }

  public Relationship getRelationshipByTargetEntity(Class<? extends Relationship> relationshipClass, String id) {
    return getRelationshipsByType(relationshipClass).get(id);
  }

  /**
   * Deactivates all relationships by setting the ending date
   *
   * @param endDate value to set for the ending date
   */
  public void deactivateAll(Date endDate) {
    for( Map<String, Relationship> relationships: relationshipByType.values() ) {
      for( Relationship relationship: relationships.values()) {
        relationship.setEnd(endDate);
      }
    }
  }
}
